/*****************************************************************************
 *   A demo example using several of the peripherals on the base board
 *
 *   Copyright(C) 2011, EE2024
 *   All rights reserved.
 *
 ******************************************************************************/
#include "LPC17xx.h"
#include <stdio.h>
#include "string.h"

#include "lpc17xx_pinsel.h"
#include "lpc17xx_gpio.h"
#include "lpc17xx_i2c.h"
#include "lpc17xx_ssp.h"
#include "lpc17xx_timer.h"
#include "lpc17xx_uart.h"
#include "led7seg.h"

#include "joystick.h"
#include "pca9532.h"
#include "acc.h"
#include "oled.h"
#include "rgb.h"
#include "light.h"

#define DARK 100
#define SHOCK 75
//each tick is 40ms
#define ALARM_TIME_DETECT 13
#define ALARM_TIME_COOP 25
#define DISPLAY_TIME 3

extern int asm_variance(int x, int mean, int reset, int* max);

uint32_t msTick = 0;
int isShock = 0;
int MODE = 0;// 0 is Detect Mode, 1 is Cooperative Mode
int light_level = 0;
int8_t z = 0;
int zmean = 0;
int zmax = 0;
int zvar = 0;
int sendVar = 0;
int max_var = 0;
int max_lux = 0;
int var[4] = {0};
uint32_t len = 0;
int lastSample = 0;
int lastSound = 0;
int alarmTime = 0;
uint8_t data = 0;
char sendStr[32];
uint8_t receiveStr[64];
char light_string[20];
char zmean_string[20];
char zmax_string[20];
char zvar_string[20];
char alarm_string[20];

#define NOTE_PIN_HIGH() GPIO_SetValue(0, 1<<26);
#define NOTE_PIN_LOW()  GPIO_ClearValue(0, 1<<26);

static void init_ssp(void)
{
	SSP_CFG_Type SSP_ConfigStruct;
	PINSEL_CFG_Type PinCfg;

	/*
	 * Initialize SPI pin connect
	 * P0.7 - SCK;
	 * P0.8 - MISO
	 * P0.9 - MOSI
	 * P2.2 - SSEL - used as GPIO
	 */
	PinCfg.Funcnum = 2;
	PinCfg.OpenDrain = 0;
	PinCfg.Pinmode = 0;
	PinCfg.Portnum = 0;
	PinCfg.Pinnum = 7;// SPI receive clock
	PINSEL_ConfigPin(&PinCfg);
	PinCfg.Pinnum = 8;// SPI MISO
	PINSEL_ConfigPin(&PinCfg);
	PinCfg.Pinnum = 9;// SPI MOSI
	PINSEL_ConfigPin(&PinCfg);
	PinCfg.Funcnum = 0;
	PinCfg.Portnum = 2;
	PinCfg.Pinnum = 2;// SPI SSEL (Slave Select)
	PINSEL_ConfigPin(&PinCfg);

	SSP_ConfigStructInit(&SSP_ConfigStruct);

	// Initialize SSP peripheral with parameter given in structure above
	SSP_Init(LPC_SSP1, &SSP_ConfigStruct);

	// Enable SSP peripheral
	SSP_Cmd(LPC_SSP1, ENABLE);

}

static void init_i2c(void)
{
	PINSEL_CFG_Type PinCfg;

	// Initialize I2C2 pin connect
	PinCfg.Funcnum = 2;
	PinCfg.Pinnum = 10;// SDA - data line
	PinCfg.Portnum = 0;
	PINSEL_ConfigPin(&PinCfg);
	PinCfg.Pinnum = 11;// SCL - clock line
	PINSEL_ConfigPin(&PinCfg);

	// Initialize I2C peripheral
	I2C_Init(LPC_I2C2, 100000);

	// Enaible I2C1 operation
	I2C_Cmd(LPC_I2C2, ENABLE);
}

void pinsel_uart3(void){
	PINSEL_CFG_Type PinCfg;
	PinCfg.Funcnum = 2;
	PinCfg.Pinnum = 0;
	PinCfg.Portnum = 0;
	PINSEL_ConfigPin(&PinCfg);
	PinCfg.Pinnum = 1;
	PINSEL_ConfigPin(&PinCfg);
}

void init_uart(void){
	UART_CFG_Type uartCfg;
	uartCfg.Baud_rate = 115200;
	uartCfg.Databits = UART_DATABIT_8;
	uartCfg.Parity = UART_PARITY_NONE;
	uartCfg.Stopbits = UART_STOPBIT_1;
	//pin select for uart3;
	pinsel_uart3();
	//supply power & setup working par.s for uart3
	UART_Init(LPC_UART3, &uartCfg);
	//enable transmit for uart3
	UART_TxCmd(LPC_UART3, ENABLE);
}

static void init_GPIO(void)
{
	// Initialize button SW4
	PINSEL_CFG_Type PinCfg;

	PinCfg.Funcnum= 0;
	PinCfg.OpenDrain= 0;
	PinCfg.Pinmode= 0;
	PinCfg.Portnum= 1;
	PinCfg.Pinnum= 31;
	PINSEL_ConfigPin(&PinCfg);

	GPIO_SetDir(1, 1<<31, 0);

	// Initialize button SW3
	PinCfg.Funcnum = 1;	// Function: EINT3
	PinCfg.OpenDrain = 0;
	PinCfg.Pinmode = 0;
	PinCfg.Portnum = 2;
	PinCfg.Pinnum = 10;
	PINSEL_ConfigPin(&PinCfg);

	//initialize the RED RGB LED
	PinCfg.Funcnum= 0;
	PinCfg.OpenDrain= 0;
	PinCfg.Pinmode= 0;
	PinCfg.Portnum= 2;
	PinCfg.Pinnum= 0;
	PINSEL_ConfigPin(&PinCfg);

	GPIO_SetDir(2, 1<<0, 1);
}

void system_init(){
	int8_t x,y,z;
	int var,max;//all temp var used to satisfy the function input

	init_i2c();
	init_uart();
	init_ssp();
	init_GPIO();
	led7seg_init();

	pca9532_init();
	joystick_init();
	acc_init();
	oled_init();
	light_init();
	light_enable();

	//Enable GPIO interrupt
	 LPC_GPIOINT->IO2IntEnF |= 1<<10;
	 //Enable EINT3 interrupt
	 NVIC_EnableIRQ(EINT3_IRQn);
	 NVIC_EnableIRQ(UART3_IRQn);

	 //initialize SysTick 20ms each tick
	 SysTick_Config(SystemCoreClock/25);

	 //initialize zmean
	 acc_read(&x,&y,&z);
	 zmean = z;

	 //initialize the asm_variance function
	 var = asm_variance(zmean,zmean,1,&max);

	 oled_clearScreen(OLED_COLOR_BLACK);
	 oled_putString(10,2,(unsigned char*)"DETECT MODE", OLED_COLOR_WHITE, OLED_COLOR_BLACK);

	 //---- Speaker ------>

	 GPIO_SetDir(2, 1<<0, 1);
	 GPIO_SetDir(2, 1<<1, 1);

	 GPIO_SetDir(0, 1<<27, 1);
	 GPIO_SetDir(0, 1<<28, 1);
	 GPIO_SetDir(2, 1<<13, 1);
	 GPIO_SetDir(0, 1<<26, 1);

	 GPIO_ClearValue(0, 1<<27); //LM4811-clk
	 GPIO_ClearValue(0, 1<<28); //LM4811-up/dn
	 GPIO_ClearValue(2, 1<<13); //LM4811-shutdn

	 //<---- Speaker ------

}

void readSensor(){
	int8_t x = 0;
	int8_t y = 0;

	light_level = light_read();
	acc_read(&x, &y, &z);
	zvar = asm_variance(z,zmean,0,&zmax);
}

void alarm(){
	//RED LED
	uint8_t led_state = (GPIO_ReadValue(2) >> 0) & 0x01;
	if (led_state==0) GPIO_SetValue(2,1<<0);
	else GPIO_ClearValue(2,1<<0);

	//sound here
	//playSong(song);
}

void oledDisplay(){
	if (msTick - lastSample > DISPLAY_TIME){
		sprintf(light_string,"Light: %u     ",light_level);
		oled_putString(10,12,(uint8_t *)light_string,OLED_COLOR_WHITE,OLED_COLOR_BLACK);

		sprintf(zmean_string,"z mean: %d    ",zmean);
		oled_putString(10,22,(uint8_t *)zmean_string,OLED_COLOR_WHITE,OLED_COLOR_BLACK);

		sprintf(zmax_string,"z max: %d     ",zmax);
		oled_putString(10,32,(uint8_t *)zmax_string,OLED_COLOR_WHITE,OLED_COLOR_BLACK);

		sprintf(zvar_string,"z var: %d     ",zvar);
		oled_putString(10,42,(uint8_t *)zvar_string,OLED_COLOR_WHITE,OLED_COLOR_BLACK);

		if (isShock) sprintf(alarm_string,"%s","ALARM    ");
		else sprintf(alarm_string,"%s","NO ALARM");
		oled_putString(10,52,(uint8_t *)alarm_string,OLED_COLOR_WHITE,OLED_COLOR_BLACK);
		lastSample = msTick;
	}
}
void checkSW4(){
	uint8_t SW4pressed = ((GPIO_ReadValue(1) >> 31) & 0x01);
	if(SW4pressed == 0){
		if (MODE ==1){
			MODE = 0;
			isShock = 0;
			alarmTime = ALARM_TIME_DETECT;
			LPC_UART3->IER = 0;  // Disable UART interrupt
			oled_putString(10,2,(unsigned char*)"DETECT MODE", OLED_COLOR_WHITE, OLED_COLOR_BLACK);
		}
		else {
			MODE = 1;
			isShock = 0;
			alarmTime = ALARM_TIME_COOP;
			LPC_UART3->IER = UART_IER_RBRINT_EN; // Enable UART interrupt
			oled_putString(10,2,(unsigned char*)"COOP MODE  ", OLED_COLOR_WHITE, OLED_COLOR_BLACK);
			max_var = 0;
			max_lux = 0;
		}
	}
}

int extractB(char* input){
	if (input[0]!='B') return 0;
	else {
		int cp = 2;//current position
		int num = 0;
		int length = strlen(input);
		int i;
		//clear var array in case less than 4 system join COOP
		for (i=0;i<4;i++){
			var[i] = 0;
		}

		for (i=0;i<4;i++){
			while (cp < length && input[cp]!=' ' && input[cp]!='\r') {
				if (input[cp]>='0' && input[cp]<='9'){
					num = num*10 + input[cp] - '0';
				}
				cp++;
			}
			var[i] = num;
			num = 0;
			cp++;
		}
	}
	return 1;
}
void SysTick_Handler(){
	msTick++;

	readSensor();
	if (light_level > max_lux) max_lux = light_level;
	if (zvar > max_var) max_var = zvar;
	if (MODE == 0 && light_level < DARK && zvar > SHOCK)
	    isShock = 1;

	if (isShock && msTick - lastSound > alarmTime){
		alarm();
		lastSound = msTick;
	}
}

void EINT3_IRQHandler(void){
	int max;
	//determine whether GPIO Interrupt P2.10 has occured
	if((LPC_GPIOINT->IO2IntStatF>>10) & 0x1){
		//stop the alarm
		isShock = 0;
		GPIO_ClearValue(2,1<<0);

		//re-initialize the asm_variance function
		max = asm_variance(zmean,zmean,1,&max);

		//clear GPIO Interrupt 2.10
		LPC_GPIOINT->IO2IntClr = 1<<10;
	}
}

void UART3_IRQHandler(void) {

	if (LPC_UART3->IIR & UART_IIR_INTID_RDA)
	{
		UART_Receive(LPC_UART3, &data, 1, NONE_BLOCKING);
		if (data != '\r')
		{
			len++;
			receiveStr[len-1] = data;
		}
		else
		{
			receiveStr[len] = 0;
			len = 0;

			if (strcmp((const char *)receiveStr,"IDQ") == 0)
				UART_SendString(LPC_UART3, (uint8_t *)"IDR 80 BADMAN\r\n");
			else if (strcmp((const char *)receiveStr,"REQ") == 0) {
				sendVar = max_var;
				sprintf(sendStr,"RER %d %d\r\n",max_var,max_lux);
				zvar = asm_variance(z,zmean,1,&zmax);
				max_var = max_lux = 0;
				UART_SendString(LPC_UART3, (uint8_t *)sendStr);
			}
			else if (extractB((char *)receiveStr)) {
				int i;
				int me = 1;
				for (i=0;i<4;i++){
					if (var[i] > sendVar) me = 0;
				}
				if (me) {
					UART_SendString(LPC_UART3, (uint8_t *)"MEE\r\n");
					isShock = 1;
				} else {
					UART_SendString(LPC_UART3, (uint8_t *)"NME\r\n");
				}
			}
			else if (strcmp((const char *)receiveStr,"SAQ") == 0) {
				isShock = 0;
				//turn off LED in case the alarm is stoped when LED is ON
				uint8_t led_state = (GPIO_ReadValue(2) >> 0) & 0x01;
				if (led_state==0) GPIO_SetValue(2,1<<0);
				else GPIO_ClearValue(2,1<<0);

				UART_SendString(LPC_UART3, (uint8_t *)"SAA\r\n");
			}
			else if (strcmp((const char *)receiveStr,"END") == 0) {
				UART_SendString(LPC_UART3, (uint8_t *)"ENA\r\n");
			}
			else
				UART_SendString(LPC_UART3, (uint8_t *)"ERROR\r\n");
		}
	}
}

int main (void) {
	system_init();

    while (1){
    	oledDisplay();
    	checkSW4();
    }//and while[1] loop

	return 0;
}

void check_failed(uint8_t *file, uint32_t line) {
	/* User can add his own implementation to report the file name and line number,
	 ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */

	/* Infinite loop */
	while(1);
}

